﻿using Mozhi.Abp.Domain.BasicData;
using System;
using System.Collections.Generic;
using System.Linq;
using Volo.Abp;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;

namespace mozhi.smarterp.Business.Sales
{
    public class SaleProductPrice : AuditedAggregateRoot<Guid>, IMultiTenant
    {
        public Guid? TenantId { get; private set; }

        public Guid? CustomerId { get; private set; }

        public Customer Customer { get; private set; }

        public string Code { get; private set; }

        public string Name { get; private set; }

        public Guid CurrencyId { get; private set; }

        public Currency Currency { get; private set; }

        public bool IncludeTax { get; private set; }

        public List<SaleProductPriceItem> Items { get; private set; }

        private SaleProductPrice() { }

        public SaleProductPrice(Guid id, string code, string name, Customer customer,  Currency currency, bool includeTax)
        {
            Id = id;

            Customer = customer;
            Currency = currency;

            CustomerId = customer?.Id;

            Code = code;
            Name = name;
            CurrencyId = Currency == null ? default : currency.Id;

            IncludeTax = includeTax;
            Items = new List<SaleProductPriceItem>();

            Validate();
        }

        public void Change(string code, string name, Customer customer, Currency currency, bool includeTax)
        {
            Customer = customer;
            Currency = currency;

            CustomerId = customer?.Id;

            Code = code;
            Name = name;
            CurrencyId = Currency == null ? default : currency.Id;

            IncludeTax = includeTax;

            Validate();
        }

        public void SetItems(List<SaleProductPriceItem> items)
        {
            if(items.IsNullOrEmpty())
                throw new ArgumentNullException("items");

            items.ForEach(x =>
            {
                AddOrUpdateItem(x);
            });

            //删除掉不存在的分录
            var itemIds = items.Select(item => item.Id).ToList();

            var deleted = Items.Where(x => !itemIds.Contains(x.Id)).ToList();

            deleted.ForEach(x => Items.ToList().Remove(x));

            //重新排序
            int index = 0;
            Items.ToList().ForEach(x => x.SetIndex(index++));

            ValidateItems();
        }

        #region
        private void Validate()
        {
            if (Customer != null)
                Customer.Validate();

            if (Currency == null)
                throw new UserFriendlyException("币别不存在", "100000");

            Currency.Validate();

            Check.NotNullOrEmpty(Code, nameof(Code));
            Check.NotNullOrEmpty(Name, nameof(Name));
        }

        private void AddOrUpdateItem(SaleProductPriceItem item)
        {
            if (!item.Product.Saleable)
                throw new UserFriendlyException($"产品：{item.Product.Code}-{item.Product.Name}不允许销售", "100000");

            var match = Items.FirstOrDefault(x => x.Id == item.Id);

            if (match == null)
            {
                match = item;

                match.CalculatePrice(IncludeTax);
                Items.Add(match);
            }

            else
            {
                match.Change(item.MinQuantity, item.MaxQuantity, item.Price, item.TaxRate, item.EffectiveDate, item.ExpirationDate);
                item.CalculatePrice(IncludeTax);
            }
        }

        protected void ValidateItems()
        {
            if (Items == null || Items.Count == 0)
                throw new UserFriendlyException("价格明细不能为空", "100000");
        }
        #endregion
    }

    public class SaleProductPriceItem : Entity<Guid>, IMultiTenant
    {
        public Guid? TenantId { get; private set; }

        public Guid ProductId { get; private set; }

        public Product Product { get; private set; }

        public Guid BasicUnitId { get; private set; }

        public decimal? MinQuantity { get; private set; }

        public decimal? MaxQuantity { get; private set; }

        public decimal Price { get; private set; }

        public Guid? TaxRateId { get; private set; }

        public TaxRate TaxRate { get; private set; }

        public decimal? TaxRateValue { get; private set; }

        public decimal PriceIncludeTax { get; private set; }

        public decimal PriceExcludeTax {  get; private set; }

        public DateTime EffectiveDate { get; private set; }

        public DateTime ExpirationDate { get; private set; }

        public int Index { get; private set; }

        private SaleProductPriceItem() { }

        public SaleProductPriceItem(Guid id, Product product, decimal? minQuantity, decimal? maxQuantity, decimal price,TaxRate taxRate, DateTime effectiveDate, DateTime expirationDate)
        {
            Id = id;
            SetProduct(product);
            SetTaxRate(taxRate);

            MinQuantity = minQuantity;
            MaxQuantity = maxQuantity;
            Price = price;

            SetTaxRate(taxRate);

            EffectiveDate = effectiveDate;
            ExpirationDate = expirationDate;

            Validate();
        }


        public void Change(decimal? minQuantity, decimal? maxQuantity, decimal price, TaxRate taxRate, DateTime effectiveDate, DateTime expirationDate)
        {
            SetTaxRate(taxRate);

            MinQuantity = minQuantity;
            MaxQuantity = maxQuantity;
            Price = price;

            SetTaxRate(taxRate);

            EffectiveDate = effectiveDate;
            ExpirationDate = expirationDate;

            Validate();
        }

        public void CalculatePrice(bool includeTax)
        {
            PriceIncludeTax = TaxRate == null ? Price : TaxRate.GetIncludeTaxValue(Price, includeTax);
            PriceExcludeTax = TaxRate == null ? Price : TaxRate.GetExcludeTaxValue(Price, includeTax);
        }

        public void SetIndex(int index)
        {
            Index = index;
        }

        #region
        private void SetTaxRate(TaxRate taxRate)
        {
            TaxRate = taxRate;

            TaxRateId = TaxRate?.Id;
            TaxRateValue = TaxRate?.Rate;

        }

        private void SetProduct(Product product)
        {
            Product = product;

            ProductId = product==null ? default : product.Id;

            BasicUnitId = product == null ? default : product.BasicUnitId;
        }

        private void Validate()
        {
            if (Product == null)
                throw new UserFriendlyException("产品不存在", "100000");

            Product.Validate();

            if (TaxRate != null)
                TaxRate.Validate();

            Check.NotDefaultOrNull<Guid>(ProductId ,nameof(ProductId));
            Check.NotDefaultOrNull<Guid>(BasicUnitId ,nameof(BasicUnitId));

            if (Price <= 0)
                throw new UserFriendlyException("单价必须大于0", "100000");

        }
        #endregion
    }
}
